package com.tanhua.manage.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tanhua.manage.exception.BusinessException;
import com.tanhua.manage.mapper.AdminMapper;
import com.tanhua.manage.pojo.Admin;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class AdminService extends ServiceImpl<AdminMapper, Admin> {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Value("${jwt.secret}")
    private String secret;

    private static final String CACHE_CODE_PREFIX = "MANAGE_CAP_";

    private static final String CACHE_KEY_TOKEN_PREFIX="MANAGE_TOKEN_";
    private static final ObjectMapper MAPPER = new ObjectMapper();


    /**
     * 将验证码保存到redis中
     * @param uuid uuid
     * @param code 验证码
     */
    public void saveVerificationCode(String uuid, String code) {

        String key = CACHE_CODE_PREFIX + uuid;
        //将验证码保存到redis中，有效时间为5分钟
        this.redisTemplate.opsForValue().set(key, code, Duration.ofMinutes(5));
    }

    /**
     * 登录
     */
    public String login(Admin admin,String uuid,String verificationCode){
        if (StrUtil.isEmpty(admin.getUsername())){
            throw new BusinessException("用户名不能为空");
        }

        //根据用户名查询数据库(拉姆达的形式) 类名    字段名          值                  查一个
        Admin source=lambdaQuery().eq(Admin::getUsername, admin.getUsername()).one();
        if (null==source){
            throw new BusinessException("用户名不存在");
        }

        if (StrUtil.isEmpty(admin.getPassword())){
            throw new BusinessException("密码不能为空");
        }

        //校验验证码是否正确
        if(StrUtil.isEmpty(uuid)||StrUtil.isEmpty(verificationCode)){
            throw new BusinessException("验证码校验错误");
        }

        //从redis中获取验证码并与传来的验证码比较是否相等
        String redisCapKey = CACHE_CODE_PREFIX + uuid;
        String code=this.redisTemplate.opsForValue().get(redisCapKey);
        if(StrUtil.isEmpty(code)||!verificationCode.equals(code)){
            throw new BusinessException("验证码校验错误");
        }

        //因为数据库查出来的密码是加密过的,所以传来的密码需要用md5方法加密和与数据库保存的密码比较
        if(!source.getPassword().equals(SecureUtil.md5(admin.getPassword()))){
            throw new BusinessException("密码错误");
        }

        //将用户名和id添加到map集合中
        Map<String, Object> claims = new HashMap<String, Object>();
        claims.put("username", source.getUsername());
        claims.put("id", source.getId());

        // 生成token
        String token = Jwts.builder()
                .setClaims(claims) //设置响应数据体
                .signWith(SignatureAlgorithm.HS256, secret) //设置加密方法和加密盐
                .compact();

        try {
            // 将token作为键名存储到redis中
            String redisTokenKey = CACHE_KEY_TOKEN_PREFIX + token;

            //将密码设置为null，不参与序列化(对象这么设置的)
            admin.setPassword(null);

            //将查出的admin对象信息转为json格式
            String redisTokenValue = MAPPER.writeValueAsString(source);
            //将数据存入redis中
            this.redisTemplate.opsForValue().set(redisTokenKey, redisTokenValue, Duration.ofDays(7));
            //返回token
            return token;
        } catch (Exception e) {
            log.error("存储token出错", e);
            return null;
        }
    }

    /**
     * 根据token从redis中获取用户信息
     */
    public Admin queryUserByToken(String token) {
        try {
            //从redis中获取用户信息
            String redisTokenKey = CACHE_KEY_TOKEN_PREFIX + token;
            String cacheData = this.redisTemplate.opsForValue().get(redisTokenKey);
            if (StrUtil.isEmpty(cacheData)) {
                return null;
            }
            // 刷新时间
            this.redisTemplate.expire(redisTokenKey, 7, TimeUnit.DAYS);
            //将json格式转为admin对象返回
            return MAPPER.readValue(cacheData, Admin.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 从redis中删除token缓存
     */
    public void removeToken(String token){
        String redisTokenKey = CACHE_KEY_TOKEN_PREFIX + token;
        this.redisTemplate.delete(redisTokenKey);
    }
}